import { Chessman } from "./Chessman";
import { cloneDeep } from "lodash";
export default class ChessKing extends Chessman {
  killer: Map<string, Chessman> = new Map();
  beSolveing: boolean;
  constructor(chessName, camp, x, y, key, chessId) {
    super(chessName, camp, x, y, key, chessId);
  }

  predictionMove(chessList, path?) {
    const res = [];
    const temp = [];
    temp.push(
      ...[
        [this.x + 1, this.y], // 右
        [this.x, this.y - 1], // 上
        [this.x, this.y + 1], // 下
        [this.x - 1, this.y], // 左
      ]
    );
    if (this.y === 9 || this.y === 2) {
      temp[2] = null;
    }
    if (this.y === 7 || this.y === 0) {
      temp[1] = null;
    }
    if (this.x === 3) {
      temp[3] = null;
    }
    if (this.x === 5) {
      temp[0] = null;
    }
    // 对面笑
    const flyKing = [];
    const it1 = chessList.values();
    let csm = null;
    do {
      csm = it1.next().value;
      if (!csm || csm.key === this.key || csm.x !== this.x) continue;
      if (csm.chessId === 4) {
        flyKing[0] = [csm.x, csm.y];
        break;
      }
    } while (csm);
    if (flyKing.length) {
      const it2 = chessList.values();
      do {
        csm = it2.next().value;
        if (!csm || csm.key === this.key || csm.x !== this.x) continue;
        if (csm.chessId !== 4) {
          const start = Math.min(this.y, flyKing[0][1]);
          const end = Math.max(this.y, flyKing[0][1]);
          if (csm.y < end && csm.y > start) {
            flyKing.splice(0, 1);
            break;
          }
        }
      } while (csm);
    }
    res.push(...this.filterChessman(temp, [...chessList]));
    res.push(...flyKing);
    return { data: this, path: res };
  }

  beCaught() {
    // 被将军
    // alert("将军");
    console.log("将军");
  }

  beSolve(chessList, killer): boolean {
    // 解将 true 死将 false 可解将
    this.beSolveing = true;
    let killerNumber = this.killer.size;
    // 尝试移动棋子挡住将军的棋子
    for (const [key, chessman] of cloneDeep(this.killer)) {
      const it1 = chessList.values();
      let csm: Chessman = null;
      let isBeSolve;
      switch (chessman.chessId) {
        case 0:
          // 处理对方是車的情况
          if (this.x === chessman.x) {
            // 車跟将在一条x轴  竖列对其
            isBeSolve = carSolve.call(
              this,
              chessList,
              this.y > chessman.y ? [chessman.y, this.y] : [this.y, chessman.y],
              "x"
            );
          } else if (this.y === chessman.y) {
            // 車跟将在一条y轴  横列对其
            isBeSolve = carSolve.call(
              this,
              chessList,
              this.x > chessman.x ? [chessman.x, this.x] : [this.x, chessman.x],
              "y"
            );
          } else {
            console.log(chessman, this, "处理错误");
          }
          break;
        case 1:
          // 处理对方是馬的情况
          // 上下 日字 左右 |工|（横日）
          if (this.y === chessman.y - 2) {
            // 馬在将下面两格  两格马脚->[chessman.x, chessman.y - 1]
            isBeSolve = horseSolve.call(
              this,
              chessList,
              [chessman.x, chessman.y - 1],
              "y"
            );
          } else if (this.y === chessman.y + 2) {
            // 馬在将上面两格  两格马脚->[chessman.x, chessman.y + 1]
            isBeSolve = horseSolve.call(
              this,
              chessList,
              [chessman.x, chessman.y + 1],
              "y"
            );
          } else if (this.x === chessman.x - 2) {
            // 馬在将左面两格  两格马脚->[chessman.x + 1, chessman.y]
            isBeSolve = horseSolve.call(
              this,
              chessList,
              [chessman.x + 1, chessman.y],
              "y"
            );
          } else if (this.x === chessman.x + 2) {
            // 馬在将右面两格  两格马脚->[chessman.x - 1, chessman.y]
            isBeSolve = horseSolve.call(
              this,
              chessList,
              [chessman.x - 1, chessman.y],
              "y"
            );
          }
          break;
        case 5:
          // 处理对方是炮的情况
          if (this.x === chessman.x) {
            // 炮跟将在一条x轴  竖列对其
            isBeSolve = cannonSolve.call(
              this,
              chessList,
              this.y > chessman.y ? [chessman.y, this.y] : [this.y, chessman.y],
              "x"
            );
          } else if (this.y === chessman.y) {
            // 炮跟将在一条y轴  横列对其
            isBeSolve = cannonSolve.call(
              this,
              chessList,
              this.x > chessman.x ? [chessman.x, this.x] : [this.x, chessman.x],
              "y"
            );
          } else {
            console.log(chessman, this, "处理错误");
          }
          break;
        case 6:
          // 处理兵
          isBeSolve = soldierSolve.call(this, chessList, [
            chessman.x,
            chessman.y,
          ]);
          break;

        default:
          break;
      }
      isBeSolve && killerNumber--;
      if (!this.killer.size) return false;
    }
    // 尝试移动将军解将
    const { path } = this.predictionMove(chessList);
    for (let i = 0; i < path.length; i++) {
      const isOk = tryMove.call(this, chessList, path[i], this);
      isOk && killerNumber--;
      if (!this.killer.size) return false;
    }
    this.beSolveing = false;
    // 尝试移动后 清空将军的棋子 || 尝试移动后 挡住所有将军的棋子
    return !this.killer.size || !!killerNumber;
  }

  // 检查是否被将军、返回值为是否为死将(判负)
  checkKiller(
    chessList: Map<string, Chessman>,
    checkBeSolve: boolean = false,
    myChessman?
  ): boolean {
    this.killer.clear();
    // 检查下一步能杀死将军的棋子
    for (const [key, chessman] of chessList) {
      if (chessman.camp === this.camp) continue;
      const { path } = chessman.predictionMove(chessList);
      // if (chessman.chessId === 4) console.log(path);
      if (
        path.some(([x, y]) => {
          if (x === this.x && this.y === y) {
            console.log(myChessman);
            // 判断当前操作是否为吃掉将军的棋子 否(继续将军) 是(判断下一颗棋子)
            return !myChessman
              ? true
              : !(myChessman.x === chessman.x && myChessman.y === chessman.y);
          } else return false;
        })
      ) {
        // if (!this.killer.size && !this.beSolveing) this.beCaught();
        this.killer.set(key, chessman);
      }
    }
    if (this.killer.size && checkBeSolve) {
      // 已被将军 尝试解将 解将 true 死将 false 可解将
      const res = this.beSolve(chessList, this.killer);
      !res && this.beCaught();
      return res;
    }
    return false;
  }
}

function carSolve(
  chessList: Map<string, Chessman>,
  position: Array<number>, // [start, end] start < end 不包头不包尾
  positionName: string // x y
): boolean {
  // 棋子移动后不会被其他的棋子将军 & (吃掉車 | 挡住車 | 将横移)
  const it1 = chessList.values();
  let csm: Chessman = null;
  const index = positionName === "x" ? 0 : 1;
  do {
    csm = it1.next().value;
    if (!csm || csm.camp !== this.camp) continue;
    const { path } = csm.predictionMove(chessList);
    const axis = this[positionName];
    const i = index === 0 ? 1 : 0;
    const saviorPath = path.find(
      (p) => p[index] === axis && p[i] > position[0] && p[i] < position[1]
    );
    const res = tryMove.call(this, chessList, saviorPath, csm);
    if (res) return true;
  } while (csm);
  return false;
}

function horseSolve(
  chessList: Map<string, Chessman>,
  position: Array<number>, // [x, y] 马脚
  positionName: string // x y
): boolean {
  const it1 = chessList.values();
  let csm: Chessman = null;
  const p = [this.x, this.y];
  p[positionName === "x" ? 0 : 1] += position;
  do {
    csm = it1.next().value;
    if (!csm || csm.camp !== this.camp) continue;
    const { path } = csm.predictionMove(chessList);
    const saviorPath = path.find(([x, y]) => p[0] === x && p[1] === y);
    const res = tryMove.call(this, chessList, saviorPath, csm);
    if (res) return true;
  } while (csm);
  return false;
}

function cannonSolve(
  chessList: Map<string, Chessman>,
  position: Array<number>, // [start, end] start < end 不包头不包尾
  positionName: string // x y
) {
  // 棋子移动后不会被其他的棋子将军 & (吃掉炮 | 挡住炮-炮架 | 将横移)
  const it1 = chessList.values();
  let csm: Chessman = null;
  const index = positionName === "x" ? 0 : 1;
  let middle = 0;
  do {
    csm = it1.next().value;
    if (!csm || csm.camp !== this.camp) continue;
    const { path } = csm.predictionMove(chessList);
    const axis = this[positionName];
    const i = index === 0 ? 1 : 0;
    const saviorPath = path.find(
      (p) => p[index] === axis && p[i] > position[0] && p[i] < position[1]
    );
    const res = tryMove.call(this, chessList, saviorPath, csm);
    if (middle > 0 && res) return true;
    if (res) middle++;
  } while (csm);
  return false;
}

function soldierSolve(
  chessList: Map<string, Chessman>,
  position: Array<number>
) {
  const it1 = chessList.values();
  let csm: Chessman = null;
  do {
    csm = it1.next().value;
    if (!csm || csm.camp !== this.camp) continue;
    const { path } = csm.predictionMove(chessList);
    const saviorPath = path.find(
      ([x, y]) => x === position[0] && y === position[1]
    );
    const res = tryMove.call(this, chessList, saviorPath, csm);
    console.log(saviorPath, res);
    if (res) return true;
  } while (csm);
  return false;
}

function tryMove(chessList, saviorPath, csm) {
  if (saviorPath) {
    // 记录移动前棋子的位置
    const prevPath = [csm.x, csm.y];
    // 尝试移动棋子
    csm.x = saviorPath[0];
    csm.y = saviorPath[1];
    let kn = this.killer.size;
    const killer = cloneDeep(this.killer);
    this.checkKiller(chessList, false, csm);
    // 模拟移动后 能将军的棋子比移动前少(解将)
    const res = kn > this.killer.size;
    // 恢复位置
    csm.x = prevPath[0];
    csm.y = prevPath[1];
    if (!res) this.killer = killer;
    return res;
  }
}
